import type { FC, PropsWithChildren } from 'react';

import { useLang } from '@/common/lang';
import ReactRouters from '@/router';
import { getBaseChildrenRoutes } from '@/router/tools';
import {
	selectActiveFirstLevelMenuKey,
	setActiveFirstLevelMenuKey
} from '@/store/modules/tabStore';

import { MixMenuContext } from './menuContext';
import { filterRoutesToMenus, getActiveFirstLevelMenuKey, getSelectKey } from './MenuUtil';

/**
 * 菜单上下文提供者组件，负责组织和分发菜单相关的全局状态。
 *
 * @param children React 子节点
 */
const MenuProvider: FC<PropsWithChildren> = ({ children }) => {
	const { routes } = ReactRouters;
	// 当前路由对象
	const route = useRoute();
	// Redux 派发方法
	const dispatch = useAppDispatch();
	// 当前语言环境
	const { locale } = useLang();
	// 当前激活的一级菜单 key
	const activeFirstLevelMenuKey = useAppSelector(selectActiveFirstLevelMenuKey);

	/**
	 * 计算所有菜单数据，依赖路由配置和语言环境。
	 *
	 * @returns 菜单数据列表
	 */
	const menus = useMemo(() => filterRoutesToMenus(getBaseChildrenRoutes(routes)), [routes, locale]);

	/** 获取一级菜单列表（去除 children 字段，仅保留一级菜单信息）。 */
	const firstLevelMenu = menus.map(menu => {
		const { children: _, ...rest } = menu;
		return rest;
	}) as App.Global.Menu[];

	/** 获取当前激活一级菜单下的子菜单列表。 */
	const childLevelMenus = menus.find(menu => menu.key === activeFirstLevelMenuKey)
		?.children as App.Global.Menu[];

	/** 获取当前选中的菜单 key 列表。 */
	const selectKey = getSelectKey(route);

	/**
	 * 设置激活的一级菜单 key。 若未指定 key，则根据当前路由自动推断。
	 *
	 * @param key 可选，指定一级菜单 key
	 */
	function changeActiveFirstLevelMenuKey(id?: string) {
		const routeKey = id ?? getActiveFirstLevelMenuKey(route);
		dispatch(setActiveFirstLevelMenuKey(routeKey ?? ''));
	}

	/** 组装菜单上下文对象，供全局消费。 */
	const mixMenuContext = {
		activeFirstLevelMenuKey, // 当前激活的一级菜单 key
		allMenus: menus, // 全部菜单数据
		childLevelMenus: childLevelMenus || [], // 当前一级菜单下的子菜单
		firstLevelMenu, // 一级菜单列表
		isActiveFirstLevelMenuHasChildren: activeFirstLevelMenuKey ? Boolean(childLevelMenus) : false, // 当前一级菜单是否有子菜单
		route, // 当前路由对象
		selectKey, // 当前选中的菜单 key
		setActiveFirstLevelMenuKey: changeActiveFirstLevelMenuKey // 设置一级菜单 key 的方法
	};

	// 提供菜单上下文给子组件
	return <MixMenuContext value={mixMenuContext}>{children}</MixMenuContext>;
};

export default MenuProvider;
